////////////////////////////////////////////////////////////////////////////
//
//  Crytek Engine Source File.
//  Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
//  File name:   trackviewdialog.cpp
//  Version:     v1.00
//  Created:     24/4/2002 by Timur.
//  Compilers:   Visual C++ 7.0
//  Description: CTrackViewDialog Implementation file.
// -------------------------------------------------------------------------
//  History:
//
////////////////////////////////////////////////////////////////////////////

#include "StdAfx.h"
#include "TrackViewDialog.h"

#include "ViewPane.h"
#include "StringDlg.h"
#include "NumberDlg.h"
#include "TVSequenceProps.h"
#include "ViewManager.h"
#include "AnimationContext.h"
#include "AnimationSerializer.h"
#include "TrackViewFindDlg.h"
#include "TrackViewUndo.h"
#include "SequenceBatchRenderDialog.h"
#include "CustomColorDialog.h"

#include "Objects\EntityObject.h"
#include "Objects\CameraObject.h"
#include "Objects\SequenceObject.h"
#include "Objects\Light.h"
#include "IViewPane.h"
#include "PluginManager.h"
#include "Util\3DConnexionDriver.h"

#include <IMovieSystem.h>
#include <IEntitySystem.h>
// CTrackViewDialog dialog

#include "Controls\TreeCtrlReport.h"

#include "Util/EditorUtils.h"

//////////////////////////////////////////////////////////////////////////
#define IDW_KEYS_PANE         AFX_IDW_CONTROLBAR_FIRST+10
#define IDW_TRACK_PROPS_PANE  AFX_IDW_CONTROLBAR_FIRST+11
#define IDW_TRACK_GRAPH_PANE  AFX_IDW_CONTROLBAR_FIRST+12
#define IDW_TRACK_SEQUENCES_PANE  AFX_IDW_CONTROLBAR_FIRST+13

#define TRACKVIEW_LAYOUT_SECTION _T("TrackViewLayout")
#define TRACKVIEW_SECTION _T("DockingPaneLayouts\\TrackView")
#define SPLITTER_ENTRY _T("Splitter")
#define VERSION_ENTRY _T("TrackViewLayoutVersion")

#define TRACKVIEW_SETTINGS_SECTION _T("TrackView")
#define SNAPPING_MODE_ENTRY _T("SnappingMode")
#define FRAME_SNAPPING_FPS_ENTRY _T("FrameSnappingFPS")
#define TICK_DISPLAY_MODE_ENTRY _T("TickDisplayMode")
#define DEFAULT_TRACKS_ENTRY _T("DefaultTracks")

#define REBAR_VERSION_ENTRY _T("TrackViewReBarVersion")
#define REBAR_BAND_ENTRY_PREFIX _T("ReBarBand")


namespace
{
	const int TRACKVIEW_LAYOUT_VERSION = 0x0001; // Bump this up on every substantial pane layout change
	const int TRACKVIEW_REBAR_VERSION = 0x0002;	// Bump this up on every substantial rebar change
}

//////////////////////////////////////////////////////////////////////////
class CTrackViewPaneClass : public TRefCountBase<IViewPaneClass>
{
	//////////////////////////////////////////////////////////////////////////
	// IClassDesc
	//////////////////////////////////////////////////////////////////////////
	virtual ESystemClassID SystemClassID() { return ESYSTEM_CLASS_VIEWPANE; };
	virtual REFGUID ClassID()
	{
		// {D21C9FE5-22D3-41e3-B84B-A377AFA0A05C}
		static const GUID guid = 
		{ 0xd21c9fe5, 0x22d3, 0x41e3, { 0xb8, 0x4b, 0xa3, 0x77, 0xaf, 0xa0, 0xa0, 0x5c } };
		return guid;
	}
	virtual const char* ClassName() { return "Track View"; };
	virtual const char* Category() { return "Editor"; };
	//////////////////////////////////////////////////////////////////////////
	virtual CRuntimeClass* GetRuntimeClass() { return RUNTIME_CLASS(CTrackViewDialog); };
	virtual const char* GetPaneTitle() { return _T("Track View"); };
	virtual EDockingDirection GetDockingDirection() { return DOCK_BOTTOM; };
	virtual CRect GetPaneRect() { return CRect(0,0,500,300); };
	virtual bool SinglePane() { return true; };
	virtual bool WantIdleUpdate() { return true; };
};

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::RegisterViewClass()
{
	GetIEditor()->GetClassFactory()->RegisterClass( new CTrackViewPaneClass );
	GetIEditor()->GetSettingsManager()->AddToolName(TRACKVIEW_LAYOUT_SECTION,"Track View");
}

IMPLEMENT_DYNCREATE(CTrackViewDialog, CBaseFrameWnd)


//////////////////////////////////////////////////////////////////////////
CString CTrackViewDialog::m_currSequenceName;
CTrackViewDialog *CTrackViewDialog::s_pTrackViewDialog = NULL;

//////////////////////////////////////////////////////////////////////////
CTrackViewDialog::CTrackViewDialog(CWnd* pParent /*=NULL*/)
{
	s_pTrackViewDialog = this;
	m_currSequence = 0;
	m_bRecord = false;
	m_bAutoRecord = false;
	m_bPause = false;
	m_bPlay = false;
	m_bReloading=false;
	m_fLastTime=-1.0f;
	ZeroStruct(m_defaulCameraObjectId);
	m_movieSystem = 0;
	m_fAutoRecordStep = 0.5f;
	GetIEditor()->RegisterNotifyListener(this);
	m_bNeedReloadSequence = false;
	m_bInLevelLoad = false;

	m_findDlg = 0;

	m_lazyInitDone = false;
	m_bEditLock = false;

	m_pNodeForTracksToolBar = NULL;

	m_defaultTracksForEntityNode.resize(GetMovieSystem()->GetEntityNodeParamCount());
	for(int i=0; i<GetMovieSystem()->GetEntityNodeParamCount(); ++i)
	{
		IAnimNode::SParamInfo paramInfo;
		GetMovieSystem()->GetEntityNodeParamInfo(i, paramInfo);
		if(paramInfo.paramId == APARAM_POS 
		|| paramInfo.paramId == APARAM_ROT
		|| paramInfo.paramId == APARAM_EVENT)	// Pos,Rot and Event tracks are on by very default.
			m_defaultTracksForEntityNode[i] = 1;
		else
			m_defaultTracksForEntityNode[i] = 0;
	}

	CRect rc(0,0,0,0);
	Create( WS_CHILD|WS_VISIBLE,rc,AfxGetMainWnd() );

	GetIEditor()->GetObjectManager()->GetLayersManager()->AddUpdateListener( functor(*this,&CTrackViewDialog::OnLayerUpdate) );
}

CTrackViewDialog::~CTrackViewDialog()
{
	if(m_findDlg)
	{
		m_findDlg->DestroyWindow();
		delete m_findDlg;
		m_findDlg = 0;
	}
	s_pTrackViewDialog = 0;
	GetIEditor()->UnregisterNotifyListener(this);
	GetIEditor()->GetObjectManager()->GetLayersManager()->RemoveUpdateListener( functor(*this,&CTrackViewDialog::OnLayerUpdate) );
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::PostNcDestroy()
{
	delete this;
}

void CTrackViewDialog::DoDataExchange(CDataExchange* pDX)
{
	__super::DoDataExchange(pDX);
}


BEGIN_MESSAGE_MAP(CTrackViewDialog, CBaseFrameWnd)
//	ON_WM_CREATE()
	ON_CBN_SELENDOK( IDC_SEQUENCES,OnChangeSequence )
	ON_COMMAND( ID_TV_PREVKEY,OnGoToPrevKey )
	ON_COMMAND( ID_TV_NEXTKEY,OnGoToNextKey )
	ON_COMMAND( ID_TV_ADDKEY,OnAddKey )
	ON_COMMAND( ID_TV_DELKEY,OnDelKey )
	ON_COMMAND( ID_TV_MOVEKEY,OnMoveKey )
	ON_COMMAND( ID_TV_SLIDEKEY,OnSlideKey )
	ON_COMMAND( ID_TV_SCALEKEY,OnScaleKey )
	ON_COMMAND( ID_TV_ADD_SEQUENCE,OnAddSequence )
	ON_COMMAND( ID_TV_DEL_SEQUENCE,OnDelSequence )
	ON_COMMAND( ID_TV_EDIT_SEQUENCE,OnEditSequence )
	ON_COMMAND( ID_TV_RECORD,OnRecord )
	ON_COMMAND( ID_TV_RECORD_AUTO,OnAutoRecord )
	ON_COMMAND( ID_TV_JUMPSTART,OnGoToStart)
	ON_COMMAND( ID_TV_JUMPEND,OnGoToEnd)
	ON_COMMAND( ID_TV_PLAY,OnPlay )
	ON_COMMAND( ID_TV_STOP,OnStop )
	ON_COMMAND( ID_TV_PAUSE,OnPause )
	ON_COMMAND(	ID_PLAY_LOOP, OnLoop)
	ON_COMMAND( ID_TV_COPYPASTEKEYS,OnCopyPasteKeys)
	ON_COMMAND( ID_ADDNODE,OnAddSelectedNode )
	ON_COMMAND( ID_ADDSCENETRACK,OnAddDirectorNode )
	ON_COMMAND( ID_FIND,OnFindNode )
	ON_COMMAND( ID_TV_SEQUENCE_NEW,OnAddSequence )
	ON_COMMAND( ID_TV_MODE_CURVEEDITOR,OnModeCurveEditor )
	ON_COMMAND( ID_TV_MODE_DOPESHEET,OnModeDopeSheet )
	ON_COMMAND( ID_TV_MODE_OPENCURVEEDITOR,OnOpenCurveEditor )
	ON_COMMAND( ID_VIEW_TICKINSECONDS,OnViewTickInSeconds )
	ON_COMMAND( ID_VIEW_TICKINFRAMES,OnViewTickInFrames )
	ON_COMMAND( ID_TV_SNAP_NONE,OnSnapNone )
	ON_COMMAND( ID_TV_SNAP_MAGNET,OnSnapMagnet )
	ON_COMMAND( ID_TV_SNAP_FRAME,OnSnapFrame )
	ON_COMMAND( ID_TV_SNAP_TICK,OnSnapTick )
	ON_COMMAND( ID_TV_SNAP_FPS,OnSnapFPS )
	ON_COMMAND( ID_TOOLS_CUSTOMIZEKEYBOARD,OnCustomize )
	ON_COMMAND( ID_TOOLS_EXPORT_SHORTCUTS, OnExportShortcuts )
	ON_COMMAND( ID_TOOLS_IMPORT_SHORTCUTS, OnImportShortcuts )
	ON_COMMAND( ID_TOOLS_BATCH_RENDER, OnBatchRender )
	ON_COMMAND( ID_TV_CREATE_LIGHT_ANIMATION_SET, OnCreateLightAnimationSet )
	ON_COMMAND( ID_TV_ADD_LIGHT_ANIMATION_NODE, OnAddLightAnimation )
	ON_COMMAND_RANGE( ID_TV_TRACKS_TOOLBAR_BASE, ID_TV_TRACKS_TOOLBAR_LAST, OnTracksToolBar )
	ON_UPDATE_COMMAND_UI(ID_TV_RECORD, OnUpdateRecord)
	ON_UPDATE_COMMAND_UI(ID_TV_RECORD_AUTO, OnUpdateRecordAuto)
	ON_UPDATE_COMMAND_UI(ID_TV_PLAY, OnUpdatePlay)
	ON_UPDATE_COMMAND_UI(ID_TV_PAUSE, OnUpdatePause)
	ON_UPDATE_COMMAND_UI(ID_PLAY_LOOP, OnUpdateLoop)
	ON_UPDATE_COMMAND_UI(ID_TV_COPYPASTEKEYS, OnUpdateCopyPasteKeys)
	ON_UPDATE_COMMAND_UI(ID_ADDNODE, OnAddSelectedNodeUpdate )
	ON_UPDATE_COMMAND_UI(ID_VIEW_TICKINSECONDS,OnUpdateViewTickInSeconds )
	ON_UPDATE_COMMAND_UI(ID_VIEW_TICKINFRAMES,OnUpdateViewTickInFrames )
	ON_UPDATE_COMMAND_UI(ID_TV_DEL_SEQUENCE,OnUpdateDelSequence)
	ON_UPDATE_COMMAND_UI(ID_TV_EDIT_SEQUENCE,OnUpdateEditSequence)
	ON_UPDATE_COMMAND_UI(ID_TOOLS_BATCH_RENDER, OnUpdateBatchRender)
	ON_UPDATE_COMMAND_UI(ID_TV_CREATE_LIGHT_ANIMATION_SET, OnUpdateCreateLightAnimationSetUI)
	ON_UPDATE_COMMAND_UI(ID_TV_ADD_LIGHT_ANIMATION_NODE, OnUpdateAddLightAnimationUI)
	ON_UPDATE_COMMAND_UI(ID_ADDSCENETRACK, OnUpdateAddDirectorNodeUI)
	ON_NOTIFY(TBN_DROPDOWN, AFX_IDW_TOOLBAR, OnToolbarDropDown)
	ON_WM_SETFOCUS()
	ON_WM_SIZE()
	ON_WM_DESTROY()
	ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipTextForTracksToolBar)
//	ON_WM_PAINT()
END_MESSAGE_MAP()

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnToolbarDropDown(NMHDR *pnhdr, LRESULT *plr)
{
	CRect rc, rc2;
	CPoint pos;
	GetCursorPos( &pos );
	NMTOOLBAR* pnmtb = (NMTOOLBAR*)pnhdr;
	// Relative to the toolbar
	if (pnmtb->iItem == ID_ADDNODE)
		m_mainToolBar.GetToolBarCtrl().GetRect( pnmtb->iItem,rc );
	else
		m_playToolBar.GetToolBarCtrl().GetRect( pnmtb->iItem,rc );
	// Get the rect of a corresponding toolbar in screen coordinate.
	// Remember that a toolbar is inside the rebar.
	for(UINT i=0; i<m_rebar.GetReBarCtrl().GetBandCount(); ++i)
	{
		m_rebar.GetReBarCtrl().GetRect(i, rc2);
		m_rebar.ClientToScreen(rc2);
		if(rc2.PtInRect(pos))
			break;
	}
	// Get the final location for a popup menu.
	rc.OffsetRect( rc2.left,rc2.top );
	pos.x = rc.left;
	pos.y = rc.bottom;

	// Switch on button command id's.
	switch (pnmtb->iItem)
	{
		case ID_TV_PLAY:
			OnPlayMenu(pos);
			break;
		case ID_TV_STOP:
			OnStopMenu(pos);
			break;
		case ID_TV_RECORD_AUTO:
			OnRecordMenu(pos);
			break;
		case ID_ADDNODE:
			OnAddEntityNodeMenu(pos);
			break;
		default:
			return;
	}
	*plr = TBDDRET_DEFAULT;
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnRecordMenu( CPoint pos )
{
	struct SScales
	{
		const char *pszText;
		float fScale;
	};
	SScales Scales[]={
		{" 1 sec ", 1.0f},
		{"1/2 sec", 1.0f/2},
		{"1/5 sec", 1.0f/5},
		{"1/10 sec", 1.0f/10},
		{"1/25 sec", 1.0f/25},
		{"1/50 sec", 1.0f/50},
		{"1/100 sec", 1.0f/100},
	};
	int nScales=sizeof(Scales)/sizeof(SScales);
	CMenu menu;
	menu.CreatePopupMenu();
	for (int i=0;i<nScales;i++)
	{
		int flags = 0;
		if (m_fAutoRecordStep == Scales[i].fScale)
			flags |= MF_CHECKED;
		menu.AppendMenu(MF_STRING|flags, i+1, Scales[i].pszText);
	}
	int cmd = CXTPCommandBars::TrackPopupMenu(&menu, 
							TPM_NONOTIFY|TPM_RETURNCMD|TPM_LEFTALIGN|TPM_RIGHTBUTTON, pos.x,pos.y, this, NULL);
	if (cmd >= 1 && cmd <= nScales)
		m_fAutoRecordStep = Scales[cmd-1].fScale;
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnPlayMenu( CPoint pos )
{
	struct SScales
	{
		const char *pszText;
		float fScale;
	};
	SScales Scales[]={
		{" 2 ", 2.0f},
		{" 1 ", 1.0f},
		{"1/2", 0.5f},
		{"1/4", 0.25f},
		{"1/8", 0.125f},
	};
	int nScales=sizeof(Scales)/sizeof(SScales);
	CMenu menu;
	menu.CreatePopupMenu();
	for (int i=0;i<nScales;i++)
	{
		int flags = 0;
		if (GetIEditor()->GetAnimation()->GetTimeScale() == Scales[i].fScale)
			flags |= MF_CHECKED;
		menu.AppendMenu(MF_STRING|flags, i+1, Scales[i].pszText);
	}
	//////////////////////////////////////////////////////////////////////////
	menu.AppendMenu(MF_SEPARATOR);
	//////////////////////////////////////////////////////////////////////////
	int flags = 0;
	if (GetIEditor()->GetAnimation()->IsPlayingToAVI())
		flags |= MF_CHECKED;
	menu.AppendMenu(MF_STRING|flags, 100, _T("Encode to AVI") );
	if (!m_aviFile.IsEmpty())
	{
		menu.AppendMenu(MF_SEPARATOR);
		menu.AppendMenu(MF_STRING|MF_GRAYED, 102, m_aviFile );
	}

	menu.AppendMenu(MF_SEPARATOR);


	bool bSequenceCamera=false;

	CViewport* pRendView = GetIEditor()->GetViewManager()->GetViewport(ET_ViewportCamera);
	if(pRendView)
		bSequenceCamera=pRendView->GetCameraObjectState();

	menu.AppendMenu(MF_STRING|((bSequenceCamera)?MF_CHECKED:MF_UNCHECKED), 200, _T("Sequence Camera") );

	int cmd = CXTPCommandBars::TrackPopupMenu(&menu, 
							TPM_NONOTIFY|TPM_RETURNCMD|TPM_LEFTALIGN|TPM_RIGHTBUTTON, pos.x,pos.y, this, NULL);
	if (cmd >= 1 && cmd <= nScales && cmd < 100)
		GetIEditor()->GetAnimation()->SetTimeScale(Scales[cmd-1].fScale);

	switch (cmd)
	{
	case 100:
		{
			if (!GetIEditor()->GetAnimation()->IsPlayingToAVI())
			{
				if (CFileUtil::SelectSaveFile( "AVI Files (*.avi)|*.avi","avi","",m_aviFile ))
				{
					GetIEditor()->GetAnimation()->PlayToAVI( true,m_aviFile );
				}
			}
			else
			{
				GetIEditor()->GetAnimation()->PlayToAVI( false );
			}
		}
		break;
	case 101:
		{
			
		}
		break;
	case 200:
		{
			if(pRendView)
				pRendView->ToggleCameraObject();
		}
		break;

	}
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnStopMenu( CPoint pos )
{
	CMenu menu;
	menu.CreatePopupMenu();
	const int MID_STOP = 100;
	const int MID_STOP_HARD = 200;
	menu.AppendMenu(MF_STRING, MID_STOP, "Stop");
	menu.AppendMenu(MF_STRING, MID_STOP_HARD, "Stop with Hard Reset");

	int cmd = CXTPCommandBars::TrackPopupMenu(&menu, 
		TPM_NONOTIFY|TPM_RETURNCMD|TPM_LEFTALIGN|TPM_RIGHTBUTTON, pos.x,pos.y, this, NULL);

	switch (cmd)
	{
	case MID_STOP:
		OnStop();
		break;
	case MID_STOP_HARD:
		{
			CAnimationContext *ac = GetIEditor()->GetAnimation();
			ac->SetTime(ac->GetMarkers().start);
			ac->SetPlaying( false );
			ac->SetRecording( false );
			if (m_currSequence != NULL)
				m_currSequence->ResetHard();
		}
		break;
	}
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnAddEntityNodeMenu( CPoint pos )
{
	CMenu menu;
	menu.CreatePopupMenu();
	IAnimNode::SParamInfo paramInfo;
	for (int i=0; i<GetMovieSystem()->GetEntityNodeParamCount(); ++i)
	{
		GetMovieSystem()->GetEntityNodeParamInfo(i, paramInfo);
		int flags = MF_STRING;
		CString trackText = paramInfo.name;
		if (m_defaultTracksForEntityNode[i] > 0)
		{
			flags |= MF_CHECKED;
			if (paramInfo.flags & IAnimNode::PARAM_MULTIPLE_TRACKS)
				trackText.Format("%s x%d", paramInfo.name, m_defaultTracksForEntityNode[i]);
		}
		menu.AppendMenu(flags, i+1, trackText);
	}

	int cmd = CXTPCommandBars::TrackPopupMenu(&menu, 
		TPM_NONOTIFY|TPM_RETURNCMD|TPM_LEFTALIGN|TPM_RIGHTBUTTON, pos.x,pos.y, this, NULL);
	if (cmd > 0)
	{
		int index = cmd - 1;
		assert(index < GetMovieSystem()->GetEntityNodeParamCount());
		GetMovieSystem()->GetEntityNodeParamInfo(index, paramInfo);
		if (paramInfo.flags & IAnimNode::PARAM_MULTIPLE_TRACKS)
		{
			CNumberDlg numDlg(this, m_defaultTracksForEntityNode[index], "Multi-track count");
			numDlg.SetInteger(true);
			numDlg.SetRange(0.0f, 10.0f);
			if (numDlg.DoModal() == IDOK)
				m_defaultTracksForEntityNode[index] = FloatToIntRet(numDlg.GetValue());
		}
		else
			m_defaultTracksForEntityNode[index] = 1 - m_defaultTracksForEntityNode[index];
	}
}

//////////////////////////////////////////////////////////////////////////
BOOL CTrackViewDialog::OnInitDialog()
{
	__super::OnInitDialog();

	CMFCUtils::LoadShortcuts(GetCommandBars(), IDR_TRACKVIEW, "TrackView");

	//////////////////////////////////////////////////////////////////////////
	// Create and setup the heightmap edit viewport and the toolbars
	GetCommandBars()->GetCommandBarsOptions()->bShowExpandButtonAlways = FALSE;
	GetCommandBars()->EnableCustomization(FALSE);

	CRect rcClient;
	GetClientRect(rcClient);

	CXTPCommandBar* pMenuBar = GetCommandBars()->SetMenu( _T("Menu Bar"),IDR_TRACKVIEW );
	pMenuBar->SetFlags(xtpFlagStretched);
	pMenuBar->EnableCustomization(TRUE);
	//////////////////////////////////////////////////////////////////////////

	CRect rc;
	InitToolbar();

	// Create splitter and track view controls.
	GetClientRect(rc);
	rc.right /= 2;
	//m_wndNodes.Create( WS_VISIBLE|WS_CHILD| TVS_FULLROWSELECT|TVS_HASBUTTONS|TVS_HASLINES|TVS_SHOWSELALWAYS|TVS_LINESATROOT,rc,this,1 );


	m_wndNodesCtrl.Create(WS_CHILD|WS_TABSTOP,CRect(0,0,200,300),this,1 );
	//CreateDockingPane( &m_wndNodesCtrl,IDW_KEYS_PANE,CRect(0,0,200,300),dockLeftOf )->SetTitle( _T("Nodes") );

	// Create key tracks dialog.
	m_wndKeys.Create( NULL,NULL,WS_VISIBLE|WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS|WS_HSCROLL,rc,this,2 );
	m_wndKeys.SetTimeRange( 0,20 );
	m_wndKeys.SetTimeScale( 100,0 );
	m_wndKeys.SetCurrTime( 1 );

	//m_wndNodes.SetKeyListCtrl( &m_wndGraph );
	//m_wndNodes.SetKeyListCtrl( &m_wndKeys );
	m_wndNodesCtrl.SetKeyListCtrl( &m_wndKeys );
	m_wndNodesCtrl.Init();

	//m_wndNodes.SetItemHeight( 16 );
	
	GetClientRect(rc);
	m_wndSplitter.CreateStatic( this,1,2,WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS );
	m_wndSplitter.SetPane( 0,0,&m_wndNodesCtrl, CSize(150, 100) );
	m_wndSplitter.SetPane( 0,1,&m_wndKeys, CSize(300, 100) );
	//m_wndSplitter.SetPane( 0,1,&m_wndGraph, CSize(300, 100) );
	m_wndSplitter.MoveWindow(&rc, TRUE);

	m_wndKeys.SetOwner(this);
	m_wndNodesCtrl.SetOwner(this);

	m_wndNodesCtrl.ShowWindow(SW_SHOW);

	//////////////////////////////////////////////////////////////////////////
	// Create Key properties docking pane.
	CXTPDockingPane *pDockPane1;
	{
		m_wndKeyProperties.Create( CTrackViewKeyPropertiesDlg::IDD,this );
		m_wndKeyProperties.PopulateVariables();
		m_wndKeyProperties.SetKeysCtrl(&m_wndKeys);
		CXTPDockingPane *pDockPane 
			= CreateDockingPane( "Key",&m_wndKeyProperties,IDW_KEYS_PANE,CRect(0,0,270,300),dockRightOf );
		pDockPane->SetOptions(xtpPaneNoCloseable);
		pDockPane1 = pDockPane;
	}

	{
		m_wndSequences.Create(WS_CHILD|WS_TABSTOP,CRect(0,0,200,300),this,1 );
		m_wndSequences.SetTrackViewDialog(this);
		CXTPDockingPane *pDockPane 
			= CreateDockingPane( "Sequences",&m_wndSequences,IDW_TRACK_SEQUENCES_PANE,CRect(0,0,270,300),dockRightOf );
		pDockPane->SetOptions(xtpPaneNoCloseable);
		GetDockingPaneManager()->HidePane(pDockPane);
	}

	{
		m_wndGraph.Create( CTrackViewCurveEditor::IDD,this );
		CXTPDockingPane *pDockPane 
			= CreateDockingPane( "Graph",&m_wndGraph,IDW_TRACK_GRAPH_PANE,CRect(0,0,270,300),dockBottomOf );
		pDockPane->SetOptions(xtpPaneNoCloseable);
		GetDockingPaneManager()->HidePane(pDockPane);
	}

	//CreateDockingPane( &m_wndSplitter,IDW_KEYS_PANE,CRect(0,0,300,500),dockTopOf );

	RecalcLayout();
	InitSequences();

	m_lazyInitDone = false;

	ReadLayouts();
	ReadMiscSettings();
	ReadReBar();

	CString cursorPosText;
	cursorPosText.Format("0.000(%dfps)", FloatToIntRet(m_wndGraph.GetFPS()));
	m_CursorPos.SetWindowText(cursorPosText);

	return TRUE;  // return TRUE unless you set the focus to a control
	// EXCEPTION: OCX Property Pages should return FALSE
}

IMovieSystem* CTrackViewDialog::GetMovieSystem()
{
	if (m_movieSystem)
	{
		return m_movieSystem;
	}
	m_movieSystem = GetIEditor()->GetMovieSystem();

	return m_movieSystem;
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::InitToolbar()
{
	m_rebar.Create(this);
	REBARBANDINFO rbi;
	ZeroMemory(&rbi,sizeof(REBARBANDINFO));
	rbi.cbSize = sizeof(REBARBANDINFO);
	rbi.fMask = RBBIM_ID;

	/// Create the main toolbar.
	m_mainToolBar.CreateEx(this, TBSTYLE_FLAT|TBSTYLE_TRANSPARENT,
		WS_CHILD|WS_VISIBLE|CBRS_TOP|CBRS_TOOLTIPS|CBRS_FLYBY|CBRS_SIZE_DYNAMIC);
	m_mainToolBar.LoadToolBar(IDR_TRACKVIEW);
	m_mainToolBar.GetToolBarCtrl().SetExtendedStyle(TBSTYLE_EX_DRAWDDARROWS);
	m_rebar.AddBar(&m_mainToolBar, "Sequence/Node:");
	rbi.wID = m_rebar.GetReBarCtrl().GetBandCount() - 1;
	m_rebar.GetReBarCtrl().SetBandInfo(rbi.wID, &rbi);

	int nIndex=m_mainToolBar.CommandToIndex(ID_ADDNODE);
	m_mainToolBar.SetButtonStyle(nIndex, m_mainToolBar.GetButtonStyle(nIndex) | TBSTYLE_DROPDOWN);

	/// Create the view toolbar
	m_viewToolBar.CreateEx(this, TBSTYLE_FLAT|TBSTYLE_TRANSPARENT,
		WS_CHILD|WS_VISIBLE|CBRS_TOP|CBRS_TOOLTIPS|CBRS_FLYBY|CBRS_SIZE_DYNAMIC);
	m_viewToolBar.LoadToolBar(IDR_TRACKVIEW_VIEW);
	m_viewToolBar.GetToolBarCtrl().SetExtendedStyle(TBSTYLE_EX_DRAWDDARROWS);
	m_rebar.AddBar(&m_viewToolBar, "View:");
	rbi.wID = m_rebar.GetReBarCtrl().GetBandCount() - 1;
	m_rebar.GetReBarCtrl().SetBandInfo(rbi.wID, &rbi);

	/// Create and set up the play toolbar.
	m_playToolBar.CreateEx(this, TBSTYLE_FLAT|TBSTYLE_TRANSPARENT,
		WS_CHILD|WS_VISIBLE|CBRS_TOP|CBRS_TOOLTIPS|CBRS_FLYBY|CBRS_SIZE_DYNAMIC);
	m_playToolBar.LoadToolBar(IDR_TRACKVIEW_PLAY);
	m_playToolBar.GetToolBarCtrl().SetExtendedStyle(TBSTYLE_EX_DRAWDDARROWS);
	m_rebar.AddBar(&m_playToolBar, "Play:");
	rbi.wID = m_rebar.GetReBarCtrl().GetBandCount() - 1;
	m_rebar.GetReBarCtrl().SetBandInfo(rbi.wID, &rbi);

	m_playToolBar.SetButtonStyle( m_playToolBar.CommandToIndex(ID_TV_RECORD),TBBS_CHECKBOX );
	m_playToolBar.SetButtonStyle( m_playToolBar.CommandToIndex(ID_TV_RECORD_AUTO),TBBS_CHECKBOX );
	m_playToolBar.SetButtonStyle( m_playToolBar.CommandToIndex(ID_TV_PLAY),TBBS_CHECKBOX );
	m_playToolBar.SetButtonStyle( m_playToolBar.CommandToIndex(ID_TV_PAUSE),TBBS_CHECKBOX );
	nIndex=m_playToolBar.CommandToIndex(ID_TV_PLAY);
	m_playToolBar.SetButtonStyle(nIndex, m_playToolBar.GetButtonStyle(nIndex) | TBSTYLE_DROPDOWN);
	nIndex=m_playToolBar.CommandToIndex(ID_TV_RECORD_AUTO);
	m_playToolBar.SetButtonStyle(nIndex, m_playToolBar.GetButtonStyle(nIndex) | TBSTYLE_DROPDOWN);
	nIndex=m_playToolBar.CommandToIndex(ID_TV_STOP);
	m_playToolBar.SetButtonStyle(nIndex, m_playToolBar.GetButtonStyle(nIndex) | TBSTYLE_DROPDOWN);

	m_bRecord = false;
	m_bPause = false;
	m_bPlay = false;

	/// Create and set up the keys toolbar.
	m_keysToolBar.CreateEx(this, TBSTYLE_FLAT|TBSTYLE_TRANSPARENT,
		WS_CHILD|WS_VISIBLE|CBRS_TOP|CBRS_TOOLTIPS|CBRS_FLYBY|CBRS_SIZE_DYNAMIC);
	m_keysToolBar.LoadToolBar(IDR_TRACKVIEW_KEYS);
	m_keysToolBar.GetToolBarCtrl().SetExtendedStyle(TBSTYLE_EX_DRAWDDARROWS);
	m_rebar.AddBar(&m_keysToolBar, "Keys:");
	rbi.wID = m_rebar.GetReBarCtrl().GetBandCount() - 1;
	m_rebar.GetReBarCtrl().SetBandInfo(rbi.wID, &rbi);

	m_keysToolBar.SetButtonStyle( m_keysToolBar.CommandToIndex(ID_TV_ADDKEY),TBBS_CHECKGROUP );
	m_keysToolBar.SetButtonStyle( m_keysToolBar.CommandToIndex(ID_TV_MOVEKEY),TBBS_CHECKGROUP );
	m_keysToolBar.SetButtonStyle( m_keysToolBar.CommandToIndex(ID_TV_SLIDEKEY),TBBS_CHECKGROUP );
	m_keysToolBar.SetButtonStyle( m_keysToolBar.CommandToIndex(ID_TV_SCALEKEY),TBBS_CHECKGROUP );
	m_keysToolBar.SetButtonStyle( m_keysToolBar.CommandToIndex(ID_TV_SNAP_NONE),TBBS_CHECKGROUP );
	m_keysToolBar.SetButtonStyle( m_keysToolBar.CommandToIndex(ID_TV_SNAP_MAGNET),TBBS_CHECKGROUP );
	m_keysToolBar.SetButtonStyle( m_keysToolBar.CommandToIndex(ID_TV_SNAP_FRAME),TBBS_CHECKGROUP );
	m_keysToolBar.SetButtonStyle( m_keysToolBar.CommandToIndex(ID_TV_SNAP_TICK),TBBS_CHECKGROUP );

	// Initially move operation is enabled.
	m_keysToolBar.GetToolBarCtrl().CheckButton( ID_TV_MOVEKEY,TRUE );

	// No snapping, by default
	m_keysToolBar.GetToolBarCtrl().CheckButton( ID_TV_SNAP_NONE,TRUE );

	/// Create the tracks toolbar
	m_tracksToolBar.CreateEx(this, TBSTYLE_FLAT|TBSTYLE_TRANSPARENT,
		WS_CHILD|WS_VISIBLE|CBRS_TOP|CBRS_TOOLTIPS|CBRS_FLYBY|CBRS_SIZE_DYNAMIC);
	m_tracksToolBar.LoadToolBar(IDR_TRACKVIEW_VIEW);	// Just use any existing tool bar resource.
	m_tracksToolBar.GetToolBarCtrl().SetExtendedStyle(TBSTYLE_EX_DRAWDDARROWS);
	m_rebar.AddBar(&m_tracksToolBar, "Tracks:");
	rbi.wID = m_rebar.GetReBarCtrl().GetBandCount() - 1;
	m_rebar.GetReBarCtrl().SetBandInfo(rbi.wID, &rbi);
	ClearTracksToolBar();															// Here, loaded buttons are cleared anyway.

	RecalcLayout();

	/// Set up the sequence combobox in the main toolbar.
	CRect rc(0,0,0,0);
	int index;
	index = m_mainToolBar.CommandToIndex(ID_TV_SEQUENCE);
	m_mainToolBar.SetButtonInfo(index, ID_TV_SEQUENCE, TBBS_SEPARATOR, 200);
	m_mainToolBar.GetItemRect(index, &rc);
	rc.top++;
	rc.bottom += 400;
	m_sequences.Create( WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_VSCROLL|CBS_DROPDOWNLIST|CBS_SORT,rc,this,IDC_SEQUENCES );
	m_sequences.SetFont( CFont::FromHandle((HFONT)gSettings.gui.hSystemFont) );
	m_sequences.SetParent( &m_mainToolBar );

	/// Set up the cursor position static control in the play toolbar. 
	rc.SetRect(0,0,0,0);
	index = m_playToolBar.CommandToIndex(ID_TV_CURSORPOS);
	m_playToolBar.SetButtonInfo(index, ID_TV_CURSORPOS, TBBS_SEPARATOR, 100);
	m_playToolBar.GetItemRect(index, &rc);
	++rc.top;

	m_CursorPos.Create("0.000", WS_CHILD|WS_VISIBLE|SS_CENTER|SS_CENTERIMAGE|SS_SUNKEN,rc,this,IDC_STATIC);

	m_CursorPos.SetFont( CFont::FromHandle((HFONT)gSettings.gui.hSystemFont) );
	m_CursorPos.SetParent( &m_playToolBar );

	/// Set up the active camera static control in the play toolbar.
	rc.SetRect(0,0,0,0);
	index = m_playToolBar.CommandToIndex(ID_TV_ACTIVE_CAMERA);
	m_playToolBar.SetButtonInfo(index, ID_TV_ACTIVE_CAMERA, TBBS_SEPARATOR, 100);
	m_playToolBar.GetItemRect(index, &rc);
	++rc.top;
	m_activeCamStatic.Create(_T("Active Camera"), WS_CHILD|WS_VISIBLE|SS_CENTER|SS_CENTERIMAGE|SS_SUNKEN,rc,this,IDC_STATIC);
	m_activeCamStatic.SetFont( CFont::FromHandle((HFONT)gSettings.gui.hSystemFont) );
	m_activeCamStatic.SetParent( &m_playToolBar );
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::InitSequences()
{
	CRect rc;
	int index;
	index = m_mainToolBar.CommandToIndex(ID_TV_SEQUENCE);
	m_mainToolBar.SetButtonInfo(index, ID_TV_SEQUENCE, TBBS_SEPARATOR, 200);
	m_mainToolBar.GetItemRect(index, &rc);
	// Expand the rectangle
	rc.left += 2;
	rc.bottom += 400;
	m_sequences.MoveWindow( rc );

	ReloadSequences();
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::InvalidateSequence()
{
	m_bNeedReloadSequence = true;
}

void CTrackViewDialog::InvalidateTrackList()
{
	if (m_wndKeys.m_hWnd)
		m_wndKeys.Invalidate();
}

//////////////////////////////////////////////////////////////////////////
static void AddTrack( IAnimNode *node )
{
	ITcbKey key;
	ZeroStruct(key);

	IAnimTrack *track = node->GetTrackForParameter(APARAM_POS);
	if (!track)
		return;

	track->SetNumKeys( 10 );
	for (int i = 0; i < track->GetNumKeys(); i++)
	{
		key.time = (frand()+1)/2.0f * 20;
		key.SetFloat( (frand()) * 100 );
		track->SetKey(i,&key);
	}

	track->SortKeys();
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::Update()
{
	if (m_bNeedReloadSequence)
	{
		m_bNeedReloadSequence = false;
		IAnimSequence *seq = GetMovieSystem()->FindSequence(m_currSequenceName);
		SetCurrentSequence( seq );
	}
	CAnimationContext *ac = GetIEditor()->GetAnimation();
	float fTime=ac->GetTime();
	m_wndKeys.SetCurrTime(fTime);
	m_wndGraph.SetCurrTime(fTime);
	if (fTime!=m_fLastTime)
	{
		m_fLastTime=fTime;
		SetCursorPosText(fTime);
	}

	// Display the name of the active camera in the static control, if any.
	// The active camera node means two conditions:
	// 1. Sequence camera is currently active.
	// 2. The camera which owns this node has been set as the current camera by the director node.
	bool bSequenceCamInUse = gEnv->pMovieSystem->GetCallback() == NULL || 
		gEnv->pMovieSystem->GetCallback()->IsSequenceCamUsed();
	EntityId camId = gEnv->pMovieSystem->GetCameraParams().cameraEntityId;
	if (camId && bSequenceCamInUse)
	{
		CEntityObject *pEditorEntity = CEntityObject::FindFromEntityId(camId);
		if (pEditorEntity)
		{
			m_activeCamStatic.SetWindowText(pEditorEntity->GetName());
		}
		else
			m_activeCamStatic.SetWindowText(_T("Active Camera"));
	}
	else
		m_activeCamStatic.SetWindowText(_T("Active Camera"));
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnGoToPrevKey()
{
	CTrackViewNodesCtrl::SItemInfo *pItemInfo=m_wndNodesCtrl.GetSelectedNode();
	if ((!pItemInfo) || (!pItemInfo->node))
		return;
	std::vector<IAnimTrack*> vecTracks;
	if (!pItemInfo->track)
	{
		for (int i=0;i<pItemInfo->node->GetTrackCount();i++)
		{
			vecTracks.push_back(pItemInfo->node->GetTrackByIndex(i));
		}
	}else
	{
		vecTracks.push_back(pItemInfo->track);
	}
	float fClosestKeyTime=-1.0f;
	float fClosestDist=1E8;
	float fCurrTime=GetIEditor()->GetAnimation()->GetTime();
	for (std::vector<IAnimTrack*>::iterator It=vecTracks.begin();It!=vecTracks.end();++It)
	{
		IAnimTrack *pTrack=(*It);
		for (int i=0;i<pTrack->GetNumKeys();i++)
		{
			float fKeyTime=pTrack->GetKeyTime(i);
			float fKeyDist=fCurrTime-fKeyTime;
			if ((fKeyDist>0.0f) && (fKeyDist<fClosestDist))
			{
				fClosestDist=fKeyDist;
				fClosestKeyTime=pTrack->GetKeyTime(i);
			}
		}
	}
	if (fClosestKeyTime>=0.0f)
		GetIEditor()->GetAnimation()->SetTime(fClosestKeyTime);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnGoToNextKey()
{
	CTrackViewNodesCtrl::SItemInfo *pItemInfo=m_wndNodesCtrl.GetSelectedNode();
	if ((!pItemInfo) || (!pItemInfo->node))
		return;
	std::vector<IAnimTrack*> vecTracks;
	if (!pItemInfo->track)
	{
		for (int i=0;i<pItemInfo->node->GetTrackCount();i++)
		{
			vecTracks.push_back(pItemInfo->node->GetTrackByIndex(i));
		}
	}else
	{
		vecTracks.push_back(pItemInfo->track);
	}
	float fClosestKeyTime=-1.0f;
	float fClosestDist=1E8;
	float fCurrTime=GetIEditor()->GetAnimation()->GetTime();
	for (std::vector<IAnimTrack*>::iterator It=vecTracks.begin();It!=vecTracks.end();++It)
	{
		IAnimTrack *pTrack=(*It);
		for (int i=0;i<pTrack->GetNumKeys();i++)
		{
			float fKeyTime=pTrack->GetKeyTime(i);
			float fKeyDist=fKeyTime-fCurrTime;
			if ((fKeyDist>0.0f) && (fKeyDist<fClosestDist))
			{
				fClosestDist=fKeyDist;
				fClosestKeyTime=pTrack->GetKeyTime(i);
			}
		}
	}
	if (fClosestKeyTime>=0.0f)
		GetIEditor()->GetAnimation()->SetTime(fClosestKeyTime);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnAddKey()
{
	m_wndKeys.SetMouseActionMode( TVMODE_ADDKEY );
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnDelKey()
{
	m_wndKeys.DelSelectedKeys();
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnMoveKey()
{
	m_wndKeys.SetMouseActionMode( TVMODE_MOVEKEY );
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnSlideKey()
{
	m_wndKeys.SetMouseActionMode( TVMODE_SLIDEKEY );
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnScaleKey()
{
	m_wndKeys.SetMouseActionMode( TVMODE_SCALEKEY );
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnAddSequence()
{
	CStringDlg dlg( "New Sequence", this );
	if (dlg.DoModal() == IDOK)
	{
		CUndo undo("Add Sequence");
		CString seq = dlg.GetString();
		if (!seq.IsEmpty() && !GetIEditor()->GetMovieSystem()->FindSequence(seq))
		{
			IAnimSequence *sequence = GetIEditor()->GetMovieSystem()->CreateSequence(seq);
			GetIEditor()->GetObjectManager()->NewObject("SequenceObject", 0, seq);
			//m_sequences.AddString( seq );
			SetCurrentSequence( sequence );
		}
	}
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::ReloadSequences()
{
	if (!GetMovieSystem())
		return;

	ClearTracksToolBar();

	CAnimationContext *ac = GetIEditor()->GetAnimation();
	if (ac->IsPlaying())
		ac->SetPlaying( false );
	if (ac->IsRecordMode())
		ac->SetRecording(false);

	m_wndSequences.Reload();

	m_bReloading=true;
	GetIEditor()->GetAnimation()->SetRecording( false );
	m_sequences.ResetContent();
	CRect seqRect;
	m_sequences.GetWindowRect(&seqRect);
	m_sequences.SetDroppedWidth( seqRect.Width() );

	CDC *dc = m_sequences.GetDC();
	if (dc)
	{
		for(int k=0; k<GetMovieSystem()->GetNumSequences(); ++k)
		{
			IAnimSequence *seq = GetMovieSystem()->GetSequence(k);
			CString fullname = seq->GetFullName();
			m_sequences.AddString(fullname);

			int nWidth = (dc->GetTextExtent( fullname )).cx + ::GetSystemMetrics(SM_CXVSCROLL) + 2*::GetSystemMetrics(SM_CXEDGE);
			if(m_sequences.GetDroppedWidth() < nWidth)
				m_sequences.SetDroppedWidth( nWidth );
		}

		m_sequences.ReleaseDC(dc);
	}

	SaveZoomScrollSettings();
	// Select current sequence.
	m_currSequence = 0;
	if (!m_currSequenceName.IsEmpty())
	{
		IAnimSequence *seq = GetMovieSystem()->FindSequence(m_currSequenceName);
		SetCurrentSequence( seq );
	}
	if (!m_currSequence && m_sequences.GetCount() > 0)
	{
		m_sequences.SetCurSel(0);
		m_sequences.GetLBText(0,m_currSequenceName);
		IAnimSequence *seq = GetMovieSystem()->FindSequence(m_currSequenceName);
		SetCurrentSequence( seq );
	}

	m_bReloading=false;
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::DeleteSequence( const CString &sSequenceName )
{
	assert(sSequenceName);
	CUndo undo("Delete Sequence");
	CBaseObject * pObj = GetIEditor()->GetObjectManager()->FindObject( sSequenceName );
	if(pObj && pObj->IsKindOf(RUNTIME_CLASS(CSequenceObject)))
	{
		GetIEditor()->GetObjectManager()->DeleteObject(pObj);
	}
	IAnimSequence *pSeq = GetMovieSystem()->FindSequence(sSequenceName);
	if (pSeq)
		GetMovieSystem()->RemoveSequence(pSeq);
	ReloadSequences();
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::AddCurrentLayer( IAnimNode *pGroupNode )
{
	if(!m_currSequence)
		return;

	// Add layer node with current layer
	CObjectLayerManager* pLayerManager = GetIEditor()->GetObjectManager()->GetLayersManager();
	CObjectLayer* pLayer = pLayerManager->GetCurrentLayer();
	const CString name = pLayer->GetName();

	IAnimNode* pAnimNode = m_currSequence->CreateNode(ANODE_LAYER);
	
	if(!pAnimNode)
		return;

	pAnimNode->SetName(name);
	pAnimNode->CreateDefaultTracks();
	pAnimNode->SetFlags( pAnimNode->GetFlags()|ANODE_FLAG_SELECTED|ANODE_FLAG_EXPANDED );

	m_wndNodesCtrl.MoveJustCreatedNodeBelowSelected();
	GetIEditor()->Notify( eNotify_OnUpdateTrackView );
	m_wndNodesCtrl.SelectNode(pAnimNode->GetName());
}

//////////////////////////////////////////////////////////////////////////
bool CTrackViewDialog::IsCurrentLayerInSequence() const
{
	if(!m_currSequence)
		return false;

	CObjectLayerManager* pLayerManager = GetIEditor()->GetObjectManager()->GetLayersManager();
	CObjectLayer* pLayer = pLayerManager->GetCurrentLayer();
	const CString name = pLayer->GetName();

	return m_currSequence->FindNodeByName(name)==0 ? false : true;
}

//////////////////////////////////////////////////////////////////////////
bool CTrackViewDialog::IsAnimNodeInCurrentSequence(EAnimNodeType nodeType) const
{
	if(!m_currSequence)
		return false;
	
	int nodeCount = m_currSequence->GetNodeCount();
	for(int i=0; i<nodeCount; ++i)
	{
		IAnimNode* pNode = m_currSequence->GetNode(i);
		if(pNode->GetType() == nodeType)
			return true;
	}

	return false;
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::UpdateSequenceLockStatus()
{
	if(IsCurrentSequenceLayerLock())
	{
		SetEditLock(true);
	}
	else
	{
		SetEditLock(false);
	}
}

//////////////////////////////////////////////////////////////////////////
bool CTrackViewDialog::IsCurrentSequenceLayerLock() const
{
	if(!m_currSequence)
		return false;

	CSequenceObject* pObj = static_cast<CSequenceObject*>(m_currSequence->GetOwner());
	if(pObj)
	{
		return pObj->GetLayer()->IsFrozen();
	}
	return false;
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::SetEditLock(bool bLock)
{
	if(m_bEditLock != bLock)
		m_wndSequences.Reload();

	m_bEditLock = bLock;

	m_wndKeys.SetEditLock(bLock);
	m_wndKeys.Invalidate();
	m_wndKeys.UpdateWindow();

	m_wndNodesCtrl.SetEditLock(bLock);
	m_wndNodesCtrl.Invalidate();
	m_wndNodesCtrl.UpdateWindow();
	m_wndNodesCtrl.RedrawControl();

	m_wndGraph.SetEditLock(bLock);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnLayerUpdate( int event,CObjectLayer *pLayer )
{
	switch (event)
	{
	case CObjectLayerManager::ON_LAYER_MODIFY:
		{
			UpdateSequenceLockStatus();
		}
		break;
	}
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnDelSequence()
{
	//CString str;
	//str.Format( 
	if (AfxMessageBox( "Delete current sequence?",MB_YESNO|MB_ICONQUESTION ) == IDYES)
	{
		int sel = m_sequences.GetCurSel();
		CString seq;
		m_sequences.GetLBText(sel,seq);
		
		m_sequences.DeleteString(sel);
		
		if (m_sequences.GetCount() > 0)
		{
			m_sequences.SetCurSel(0);
		}
		OnChangeSequence();
		DeleteSequence(seq);
	}
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnEditSequence()
{
	// Edit current sequence.
	if (!m_currSequence)
		return;

	CTVSequenceProps dlg( m_currSequence,this );
	if (dlg.DoModal() == IDOK)
	{
		// Sequence updated.
		ReloadSequences();
	}
	m_wndKeys.Invalidate();
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnChangeSequence()
{
	int sel = m_sequences.GetCurSel();
	if (sel == LB_ERR)
	{
		SetCurrentSequence( 0 );
		return;
	}
	CString name;
	m_sequences.GetLBText( sel,name );
	// Display current sequence.
	IAnimSequence *seq = GetMovieSystem()->FindSequence(name);
	if (seq != m_currSequence)
	{
		SetCurrentSequence( seq );
	}
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::SetCurrentSequence( IAnimSequence *curr )
{
	bool bChanged = m_currSequence != curr;
	if (bChanged && m_currSequence)
	{
		m_currSequence->Reset(true);
		SaveZoomScrollSettings();
	}
	if (curr)
	{
		m_currSequence = curr;
		GetIEditor()->GetAnimation()->SetSequence( m_currSequence );
		string fullname = curr->GetFullName();
		m_currSequenceName = fullname.c_str();

		//m_wndNodes.SetSequence( m_currSequence );
		m_wndKeyProperties.SetSequence( m_currSequence );
		m_wndNodesCtrl.SetSequence( m_currSequence );
		m_wndKeys.SetSequence( m_currSequence );
		Range timeRange = m_currSequence->GetTimeRange();
		m_wndKeys.SetTimeRange( timeRange.start,timeRange.end );
		m_wndKeys.SetStartMarker( timeRange.start );
		m_wndKeys.SetEndMarker( timeRange.end );
		m_wndKeys.SetTimeScale( m_wndKeys.GetTimeScale(),0 );
		m_wndGraph.SetSequence( m_currSequence );
		m_wndSequences.SetCurrentSequence( m_currSequence );
		
		CSequenceObject* pObj = static_cast<CSequenceObject*>(m_currSequence->GetOwner());
		if (pObj && pObj->HasValidZoomScrollSettings())
		{
			CSequenceObject::CZoomScrollSettings settings;
			pObj->GetZoomScrollSettings(settings);
			m_wndKeys.SetTimeScale(settings.dopeSheetZoom, 0);
			m_wndKeys.SetScrollOffset(settings.dopeSheetHScroll);
			m_wndNodesCtrl.RestoreVerticalScrollPos(settings.nodesListVScroll);
			m_wndNodesCtrl.SyncKeyCtrl();
			m_wndGraph.GetSplineCtrl().SetZoom(settings.curveEditorZoom);
			m_wndGraph.GetSplineCtrl().SetScrollOffset(settings.curveEditorScroll);
		}

		m_sequences.SelectString(-1,m_currSequenceName);
	}
	else
	{
		m_currSequence = curr;
		GetIEditor()->GetAnimation()->SetSequence( 0 );
		m_currSequenceName = "";
		m_wndNodesCtrl.SetSequence(0);
		//m_wndNodes.SetSequence( 0 );
		m_wndKeys.SetSequence( 0 );
		m_wndKeyProperties.SetSequence( 0 );
		m_wndGraph.SetSequence( 0 );
	}
	if (bChanged)
	{
		ClearTracksToolBar();

		// Notify all objects to update their track gizmos.
		GetIEditor()->GetObjectManager()->SendEvent( EVENT_UPDATE_TRACKGIZMO );

		UpdateSequenceLockStatus();
	}
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnRecord()
{
	CAnimationContext *ac = GetIEditor()->GetAnimation();
	ac->SetRecording( !ac->IsRecording() );
	m_wndKeys.Invalidate();
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnAutoRecord()
{
	CAnimationContext *ac = GetIEditor()->GetAnimation();
	ac->SetAutoRecording( !ac->IsRecording(),m_fAutoRecordStep );
	m_wndKeys.Invalidate();
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnGoToStart()
{
	CAnimationContext *ac = GetIEditor()->GetAnimation();
	ac->SetTime(ac->GetMarkers().start);
	ac->SetPlaying( false );
	ac->SetRecording( false );

	if (m_currSequence != NULL)
	{
		// Reset sequence to the beginning.
		m_currSequence->Reset(true);
	}

	// Restore default camera in view.
	//GetIEditor()->GetViewManager()->SetCameraObjectId( m_defaulCameraObjectId );
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnGoToEnd()
{
	CAnimationContext *ac = GetIEditor()->GetAnimation();
	ac->SetTime(ac->GetMarkers().end);
	ac->SetPlaying( false );
	ac->SetRecording( false );

	if (m_currSequence != NULL)
	{
		// Reset sequence to the beginning.
		m_currSequence->Reset(true);
	}

	// Restore default camera in view.
	//GetIEditor()->GetViewManager()->SetCameraObjectId( m_defaulCameraObjectId );
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnPlay()
{
	m_defaulCameraObjectId = GetIEditor()->GetViewManager()->GetCameraObjectId();

	CAnimationContext *ac = GetIEditor()->GetAnimation();
	if (!ac->IsPlaying())
	{
		ac->SetPlaying( true );
		if (m_currSequence)
		{
			float fps = m_wndGraph.GetFPS();
			const float THIRTY_FPS_BY_DEFAULT = 0.033333f;
			float dt = fps == 0 ? THIRTY_FPS_BY_DEFAULT : 1.0f / float(fps);
			m_currSequence->SetFixedTimeStep(dt);
		}
	}
	else
		ac->SetPlaying( false );

	// Set current camera params.
	//OnSetCamera( GetMovieSystem()->GetCameraParams() );
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnStop()
{
	CAnimationContext *ac = GetIEditor()->GetAnimation();

	if (ac->IsPlaying())
		ac->SetPlaying( false );
	else
		OnGoToStart();
	ac->SetRecording( false );

	// Restore default camera in view.
	//GetIEditor()->GetViewManager()->SetCameraObjectId( m_defaulCameraObjectId );
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnPause()
{
	CAnimationContext *ac = GetIEditor()->GetAnimation();
	if (ac->IsPaused())
		ac->Resume();
	else
		ac->Pause();
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnLoop()
{
	CAnimationContext *ac = GetIEditor()->GetAnimation();
	ac->SetLoopMode(!ac->IsLoopMode());
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnCopyPasteKeys()
{
	if (!m_wndKeys.CopyPasteKeys())
		AfxMessageBox("Copying of keys failed.", MB_ICONEXCLAMATION | MB_OK);
}

void CTrackViewDialog::OnSetFocus(CWnd* pOldWnd)
{
	//__super::OnSetFocus(pOldWnd);

	//if (AfxGetMainWnd())
		//AfxGetMainWnd()->SetFocus();
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnUpdateRecord( CCmdUI* pCmdUI )
{
	if (GetIEditor()->GetAnimation()->IsRecordMode())
		pCmdUI->SetCheck(TRUE);
	else
		pCmdUI->SetCheck(FALSE);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnUpdateRecordAuto( CCmdUI* pCmdUI )
{
	if (GetIEditor()->GetAnimation()->IsAutoRecording())
		pCmdUI->SetCheck(TRUE);
	else
		pCmdUI->SetCheck(FALSE);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnUpdatePlay( CCmdUI* pCmdUI )
{
	if (GetIEditor()->GetAnimation()->IsPlayMode())
		pCmdUI->SetCheck(TRUE);
	else
		pCmdUI->SetCheck(FALSE);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnUpdatePause( CCmdUI* pCmdUI )
{
	if (GetIEditor()->GetAnimation()->IsPaused())
		pCmdUI->SetCheck(TRUE);
	else
		pCmdUI->SetCheck(FALSE);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnUpdateLoop( CCmdUI* pCmdUI )
{
	if (GetIEditor()->GetAnimation()->IsLoopMode())
		pCmdUI->SetCheck(TRUE);
	else
		pCmdUI->SetCheck(FALSE);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnUpdateCopyPasteKeys( CCmdUI* pCmdUI )
{
	// deprecated. This button will be removed.
	pCmdUI->Enable(false);//m_wndKeys.CanCopyPasteKeys());
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnEditorNotifyEvent( EEditorNotifyEvent event )
{
	switch (event)
	{
	case eNotify_OnBeginNewScene:
	case eNotify_OnCloseScene:
		SetCurrentSequence(NULL);
		break;
	case eNotify_OnBeginSceneOpen:
		m_bInLevelLoad = true;
		break;
	case eNotify_OnEndSceneOpen:
		m_bInLevelLoad = false;
		ReloadSequences();
		break;
	case eNotify_OnMissionChange:
		if (!m_bInLevelLoad)
			ReloadSequences();
		break;
	case eNotify_OnUpdateTrackView:
		if (!m_bInLevelLoad)
			ReloadSequences();
		break;
	case eNotify_OnIdleUpdate:
		Update();
		break;
	case eNotify_OnUpdateTrackViewKeys:
		if (!m_bInLevelLoad)
		{
			InvalidateTrackList();
			GetIEditor()->GetAnimation()->ForceAnimation();
		}
		break;
	case eNotify_OnUpdateTVKeySelection:
		if (m_currSequence && !m_bInLevelLoad)
			m_wndKeyProperties.OnKeySelectionChange();
		break;
	case eNotify_OnQuit:
		SaveLayouts();
		SaveMiscSettings();
		SaveReBar();
		break;
	}
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnDestroy()
{
	SaveLayouts();
	SaveMiscSettings();
	SaveReBar();

	__super::OnDestroy();
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnAddSelectedNode()
{
	if (!m_currSequence)
		return;

	CTrackViewNodesCtrl::SItemInfo * pSii = m_wndNodesCtrl.GetSelectedNode();
	IAnimNode *pGroupNode = NULL;
	if (pSii && pSii->node &&
		(pSii->node->GetType() == ANODE_GROUP || pSii->node->GetType() == ANODE_SCENE))
	{
		pGroupNode = pSii->node;
	}
	AddSelectedNodes(pGroupNode);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnAddDirectorNode()
{
	if (!m_currSequence)
		return;

	//m_wndNodes.AddSceneNodes();
	CreateAnimNode( ANODE_SCENE,GetAvailableNameForDirectorNode(),0 );
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnFindNode()
{
	//CTrackViewFindDlg dlg;
	//dlg.DoModal();
	if(!m_findDlg)
	{
		m_findDlg = new CTrackViewFindDlg;
		if(m_findDlg)
		{
			m_findDlg->Create(CTrackViewFindDlg::IDD, 0);
			m_findDlg->Init(this);
		}
	}

	if(m_findDlg)
	{
		m_findDlg->FillData();
		m_findDlg->ShowWindow(SW_SHOW);
	}
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnAddSelectedNodeUpdate( CCmdUI* pCmdUI )
{
	bool bLightAnimationSetActive = (m_currSequenceName == LIGHT_ANIMATION_SET_NAME) 
		&& (m_currSequence->GetFlags() & IAnimSequence::LIGHT_ANIMATION_SET);

	if (GetIEditor()->GetSelection()->IsEmpty() || !m_currSequence || bLightAnimationSetActive)
		pCmdUI->Enable(FALSE);
	else
		pCmdUI->Enable(TRUE);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::SnapToNode(const char * sName)
{
	m_wndNodesCtrl.SelectNode(sName, true);
}

//////////////////////////////////////////////////////////////////////////
BOOL CTrackViewDialog::PreTranslateMessage( MSG* pMsg )
{
	if (pMsg->message == WM_INPUT)
	{
		static C3DConnexionDriver* p3DConnexionDriver = 0;

		if (!p3DConnexionDriver)
		{
			p3DConnexionDriver = (C3DConnexionDriver*)GetIEditor()->GetPluginManager()->GetPluginByGUID( "{AD109901-9128-4ffd-8E67-137CB2B1C41B}" );
		}
		if (p3DConnexionDriver)
		{
			S3DConnexionMessage msg;
			if (p3DConnexionDriver->GetInputMessageData( pMsg->lParam,msg ))
			{
				if (msg.bGotRotation)
				{
					//float fTime = m_wndKeys.GetCurrTime();
					float fTime = GetIEditor()->GetAnimation()->GetTime();
					//float fDelta = msg.vRotate[1] * msg.vRotate[1] * 0.1f;
					float fDelta2 = msg.vRotate[2] * 0.1f;
					//if (msg.vRotate[1] < 0)
						//fTime += fDelta + fDelta2;
					//else
						//fTime -= fDelta + fDelta2;

					fTime += fDelta2;

					//m_wndKeys.SetCurrTime(fTime);

					GetIEditor()->GetAnimation()->SetTime( fTime );
				}
			}
		}
	}
	return __super::PreTranslateMessage(pMsg);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::AddSelectedNodes( IAnimNode *pGroupNode )
{
	if (!m_currSequence)
		return;

	CUndo undo("Add Anim Node(s)");
	CUndo::Record( new CUndoAnimSequenceObject(m_currSequence) );

	IAnimNode *pJustCreatedNode = NULL;
	// Add selected nodes.
	CSelectionGroup *sel = GetIEditor()->GetSelection();
	for (int i = 0; i < sel->GetCount(); i++)
	{
		CBaseObject *obj = sel->GetObject(i);
		if (!obj)
			continue;

		// Check if object already assigned to some AnimNode.
		IAnimNode *pExistingNode = obj->GetAnimNode();
		if (pExistingNode)
		{
			// If it's the case, check if this and the existing one will have a same
			// owning director or not.
			IAnimNode *pOwningDirectorOfIt = pExistingNode->HasDirectorAsParent();
			IAnimNode *pOwningDirectorOfThis = NULL;
			if (pGroupNode)
			{
				if (pGroupNode->GetType() == ANODE_SCENE)
					pOwningDirectorOfThis = pGroupNode;
				else
					pOwningDirectorOfThis = pGroupNode->HasDirectorAsParent();
			}
			// If they're same or any of them doesn't belong to any director, 
			// this creation is rejected.
			if (pOwningDirectorOfIt == NULL ||
				pOwningDirectorOfThis == NULL ||
				pOwningDirectorOfIt == pOwningDirectorOfThis)
				continue;
		}

		EAnimNodeType nodeType = ANODE_ENTITY;
		if (obj->IsKindOf( RUNTIME_CLASS(CCameraObject) ))
		{
			nodeType = ANODE_CAMERA;
		}
		else if (obj->IsKindOf( RUNTIME_CLASS(CEntityObject) ))
		{
			CEntityObject* pEntity = static_cast<CEntityObject*>(obj);

			if( pEntity->IsLight() )
				nodeType = ANODE_LIGHT;
			else
				nodeType = ANODE_ENTITY;
		}
		else
		{
			// Not supported
			continue;
		}

		IAnimNode *pAnimNode = m_currSequence->CreateNode( nodeType );
		if (!pAnimNode)
			continue;
		pJustCreatedNode = pAnimNode;

		pAnimNode->SetName( obj->GetName() );
		pAnimNode->SetNodeOwner( (CEntityObject*)obj );
		pAnimNode->SetEntityGuid( ToEntityGuid(obj->GetId()) );

		if(obj->GetLookAt() && obj->GetLookAt()->IsKindOf(RUNTIME_CLASS(CEntityObject)))
		{
			CEntityObject *target = (CEntityObject*)obj->GetLookAt();
			pAnimNode->SetEntityGuidTarget( ToEntityGuid( target->GetId() ));
		}
		if(obj->GetLookAtSource() && obj->GetLookAtSource()->IsKindOf(RUNTIME_CLASS(CEntityObject)))
		{
			CEntityObject *source = (CEntityObject*)obj->GetLookAtSource();
			pAnimNode->SetEntityGuidSource( ToEntityGuid( source->GetId() ));
		}

		if (nodeType == ANODE_ENTITY)
			CreateDefaultTracksForEntityNode(pAnimNode);
		else
			pAnimNode->CreateDefaultTracks();

		// Force default parameters.
		CEntityObject *pEntity = static_cast<CEntityObject*>(obj);
		QuatT parentXform, relXform;
		if (pEntity->GetBoneAttachTransforms(parentXform, relXform))
		{
			// If the owner is an bone-attached entity, 
			// enable the bone link xform by default and set the default pos/rot accordingly.
			pAnimNode->SetPos(0,relXform.t);
			pAnimNode->SetRotate(0,relXform.q);
			pAnimNode->EnableBoneLinkTransform(true);
		}
		else
		{
			pAnimNode->SetPos(0,obj->GetPos());
			pAnimNode->SetRotate(0,obj->GetRotation());
		}
		pAnimNode->SetScale(0,obj->GetScale());
		pAnimNode->SetFlags( pAnimNode->GetFlags()|ANODE_FLAG_SELECTED|ANODE_FLAG_EXPANDED );

		if (nodeType == ANODE_CAMERA)
		{
			float fov = static_cast<CCameraObject*>(obj)->GetFOV();
			pAnimNode->SetParamValue( 0,APARAM_FOV,RAD2DEG(fov) );
		}
		else if (nodeType == ANODE_LIGHT)
		{
			IVariable *pRadiusVar = static_cast<CEntityObject*>(obj)->GetLightVariable("Radius");
			if (pRadiusVar)
			{
				float radius;
				pRadiusVar->Get(radius);
				pAnimNode->SetParamValue(0, APARAM_LIGHT_RADIUS, radius);
			}
			IVariable *pColorGroup = static_cast<CEntityObject*>(obj)->GetLightVariable("Color");
			if (pColorGroup)
			{
				for (int k=0; k<pColorGroup->NumChildVars(); ++k)
				{
					IVariable* pChildVar = pColorGroup->GetChildVar(k);
					if (pChildVar == NULL)
						continue;
					CString childName(pChildVar->GetName());
					if (childName == "clrDiffuse" || childName == "clrColor")
					{
						Vec3 color;
						pChildVar->Get(color);
						COLORREF colorRef = CCustomColorDialog::LinearToGamma(ColorF(color));
						pAnimNode->SetParamValue(0, APARAM_LIGHT_DIFFUSECOLOR, 
							Vec3((float)GetRValue(colorRef), (float)GetGValue(colorRef), (float)GetBValue(colorRef)));
						break;
					}
				}
			}
		}

		// Update&Create track gizmo
		obj->OnEvent( EVENT_UPDATE_TRACKGIZMO );

		pAnimNode->SetParent(pGroupNode);
	}

	if (pJustCreatedNode)
	{
		if (sel->GetCount() == 1)
			m_wndNodesCtrl.MoveJustCreatedNodeBelowSelected();
		GetIEditor()->Notify( eNotify_OnUpdateTrackView );
		m_wndNodesCtrl.SelectNode(pJustCreatedNode->GetName());
	}
}

//////////////////////////////////////////////////////////////////////////
IAnimNode * CTrackViewDialog::CreateAnimNode( EAnimNodeType nodeType,const char *sName,IAnimNode *pGroupNode )
{
	if (!m_currSequence)
		return NULL;

	CUndo undo("Add Node");
	CUndo::Record( new CUndoAnimSequenceObject(m_currSequence) );

	IAnimNode *pAnimNode = m_currSequence->CreateNode( nodeType );
	if (pAnimNode)
	{
		pAnimNode->SetName( sName );
		pAnimNode->CreateDefaultTracks();
		pAnimNode->SetFlags( pAnimNode->GetFlags()|ANODE_FLAG_SELECTED|ANODE_FLAG_EXPANDED );
		pAnimNode->SetParent(pGroupNode);
		m_wndNodesCtrl.MoveJustCreatedNodeBelowSelected();
		GetIEditor()->Notify( eNotify_OnUpdateTrackView );
		m_wndNodesCtrl.SelectNode(pAnimNode->GetName());
	}
	return pAnimNode;
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnModeDopeSheet()
{
	if (GetDockingPaneManager()->FindPane(IDW_TRACK_GRAPH_PANE))
		GetDockingPaneManager()->DestroyPane(IDW_TRACK_GRAPH_PANE);
	m_wndGraph.ShowWindow(SW_HIDE);
	m_wndGraph.SetDlgCtrlID(1);
	m_wndSplitter.SetPane( 0,1,&m_wndKeys, CSize(300, 100) );
	m_wndKeys.ShowWindow(SW_SHOW);
	
	m_wndSplitter.RecalcLayout();
	m_wndGraph.SetSequence(0);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnModeCurveEditor()
{
	if (GetDockingPaneManager()->FindPane(IDW_TRACK_GRAPH_PANE))
		GetDockingPaneManager()->DestroyPane(IDW_TRACK_GRAPH_PANE);
	m_wndKeys.ShowWindow(SW_HIDE);
	m_wndKeys.SetDlgCtrlID(1);
	m_wndSplitter.SetPane( 0,1,&m_wndGraph, CSize(300, 100) );
	m_wndGraph.ShowWindow(SW_SHOW);
	m_wndSplitter.RecalcLayout();
	m_wndGraph.SetSequence(m_currSequence);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnOpenCurveEditor()
{
	OnModeDopeSheet();
	if (!GetDockingPaneManager()->FindPane(IDW_TRACK_GRAPH_PANE))
	{
		CXTPDockingPane *pDockPane 
			= CreateDockingPane( "Graph",&m_wndGraph,IDW_TRACK_GRAPH_PANE,CRect(0,0,270,300),dockBottomOf );
		pDockPane->SetOptions(xtpPaneNoCloseable);
	}
	m_wndGraph.SetSequence(m_currSequence);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnSnapNone()
{
	m_wndKeys.SetSnappingMode(TVKEY_SNAP_NONE);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnSnapMagnet()
{
	m_wndKeys.SetSnappingMode(TVKEY_SNAP_MAGNET);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnSnapFrame()
{
	m_wndKeys.SetSnappingMode(TVKEY_SNAP_FRAME);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnSnapTick()
{
	m_wndKeys.SetSnappingMode(TVKEY_SNAP_TICK);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnSnapFPS()
{
	float fps = m_wndGraph.GetFPS();
	CNumberDlg cDialog( this,fps,"Frame rate for frame snapping" );
	cDialog.SetInteger(true);
	cDialog.SetRange(1.0f, 120.0f);

	if (cDialog.DoModal() == IDOK)
	{
		fps = cDialog.GetValue();
		m_wndKeys.SetSnapFPS(FloatToIntRet(fps));
		m_wndGraph.SetFPS(fps);
		SetCursorPosText(m_wndKeys.GetCurrTime());
	}
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnSize( UINT nType, int cx, int cy )
{
	__super::OnSize( nType,cx,cy );

	if (cx > 0 && cy > 0
	&& m_lazyInitDone == false)
	{
		CRect rc;
		int index;
		index = m_mainToolBar.CommandToIndex(ID_TV_SEQUENCE);
		m_mainToolBar.SetButtonInfo(index, ID_TV_SEQUENCE, TBBS_SEPARATOR, 200);
		m_mainToolBar.GetItemRect(index, &rc);
		// Expand the rectangle
		rc.left += 2;
		rc.bottom += 400;
		m_sequences.MoveWindow( rc );

		rc.SetRect(0,0,0,0);
		index = m_playToolBar.CommandToIndex(ID_TV_CURSORPOS);
		m_playToolBar.SetButtonInfo(index, ID_TV_CURSORPOS, TBBS_SEPARATOR, 100);
		m_playToolBar.GetItemRect(index, &rc);
		++rc.top;
		m_CursorPos.MoveWindow( rc );

		rc.SetRect(0,0,0,0);
		index = m_playToolBar.CommandToIndex(ID_TV_ACTIVE_CAMERA);
		m_playToolBar.SetButtonInfo(index, ID_TV_ACTIVE_CAMERA, TBBS_SEPARATOR, 100);
		m_playToolBar.GetItemRect(index, &rc);
		++rc.top;
		m_activeCamStatic.MoveWindow( rc );

		m_wndNodesCtrl.SyncKeyCtrl();

		m_lazyInitDone = true;
	}
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnViewTickInSeconds()
{
	m_wndKeys.SetTickDisplayMode(TVTICK_INSECONDS);
	m_wndGraph.SetTickDisplayMode(TVTICK_INSECONDS);
	SetCursorPosText(GetIEditor()->GetAnimation()->GetTime());
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnViewTickInFrames()
{
	m_wndKeys.SetTickDisplayMode(TVTICK_INFRAMES);
	m_wndGraph.SetTickDisplayMode(TVTICK_INFRAMES);
	SetCursorPosText(GetIEditor()->GetAnimation()->GetTime());
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnUpdateViewTickInSeconds( CCmdUI* pCmdUI )
{
	if (m_wndKeys.GetTickDisplayMode() == TVTICK_INSECONDS)
		pCmdUI->SetCheck(TRUE);
	else
		pCmdUI->SetCheck(FALSE);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnUpdateViewTickInFrames( CCmdUI* pCmdUI )
{
	if (m_wndKeys.GetTickDisplayMode() == TVTICK_INFRAMES)
		pCmdUI->SetCheck(TRUE);
	else
		pCmdUI->SetCheck(FALSE);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnUpdateDelSequence( CCmdUI* pCmdUI )
{
	pCmdUI->Enable(m_bEditLock ? FALSE : TRUE);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnUpdateEditSequence( CCmdUI* pCmdUI )
{
	bool bLightAnimationSetActive = (m_currSequenceName == LIGHT_ANIMATION_SET_NAME) 
		&& (m_currSequence->GetFlags() & IAnimSequence::LIGHT_ANIMATION_SET);

	if (m_bEditLock || bLightAnimationSetActive)
		pCmdUI->Enable(FALSE);
	else
		pCmdUI->Enable(TRUE);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::SaveMiscSettings() const
{
	AfxGetApp()->WriteProfileInt(TRACKVIEW_SETTINGS_SECTION, SNAPPING_MODE_ENTRY, (int)m_wndKeys.GetSnappingMode());
	float fps = m_wndGraph.GetFPS();
	AfxGetApp()->WriteProfileBinary(TRACKVIEW_SETTINGS_SECTION, FRAME_SNAPPING_FPS_ENTRY, (LPBYTE)&fps, sizeof(float));
	AfxGetApp()->WriteProfileInt(TRACKVIEW_SETTINGS_SECTION, TICK_DISPLAY_MODE_ENTRY, (int)m_wndKeys.GetTickDisplayMode());
	AfxGetApp()->WriteProfileBinary(TRACKVIEW_SETTINGS_SECTION, DEFAULT_TRACKS_ENTRY, 
		(LPBYTE)&m_defaultTracksForEntityNode[0], sizeof(uint32)*m_defaultTracksForEntityNode.size());
}
//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::ReadMiscSettings()
{
	ESnappingMode snapMode = (ESnappingMode)(AfxGetApp()->GetProfileInt(TRACKVIEW_SETTINGS_SECTION, SNAPPING_MODE_ENTRY, TVKEY_SNAP_NONE));
	m_wndKeys.SetSnappingMode(snapMode);
	if(snapMode == TVKEY_SNAP_NONE)
		m_keysToolBar.GetToolBarCtrl().CheckButton( ID_TV_SNAP_NONE,TRUE );
	else if(snapMode == TVKEY_SNAP_MAGNET)
		m_keysToolBar.GetToolBarCtrl().CheckButton( ID_TV_SNAP_MAGNET,TRUE );
	else if(snapMode == TVKEY_SNAP_TICK)
		m_keysToolBar.GetToolBarCtrl().CheckButton( ID_TV_SNAP_TICK,TRUE );
	else if(snapMode == TVKEY_SNAP_FRAME)
		m_keysToolBar.GetToolBarCtrl().CheckButton( ID_TV_SNAP_FRAME,TRUE );

	LPBYTE pData=NULL; UINT bytes=0;
	if(AfxGetApp()->GetProfileBinary(TRACKVIEW_SETTINGS_SECTION, FRAME_SNAPPING_FPS_ENTRY, &pData, &bytes))
	{
		float fps = *(float*)pData;
		m_wndKeys.SetSnapFPS(FloatToIntRet(fps));
		m_wndGraph.SetFPS(fps);

		// CRT memory delete. Needed only for function that allocate CRT memory, like CWinApp::GetProfileBinary, which would conflict with Crytek's memory manager.
		EditorMemoryUtils::operator delete[](pData);
	}
	
	ETVTickMode tickMode = (ETVTickMode)(AfxGetApp()->GetProfileInt(TRACKVIEW_SETTINGS_SECTION, TICK_DISPLAY_MODE_ENTRY, TVTICK_INSECONDS));
	m_wndKeys.SetTickDisplayMode(tickMode);
	m_wndGraph.SetTickDisplayMode(tickMode);

	if(AfxGetApp()->GetProfileBinary(TRACKVIEW_SETTINGS_SECTION, DEFAULT_TRACKS_ENTRY, &pData, &bytes))
	{
		if(bytes == sizeof(uint32)*m_defaultTracksForEntityNode.size())
			memcpy(&m_defaultTracksForEntityNode[0], pData, bytes);

		// CRT memory delete. Needed only for function that allocate CRT memory, like CWinApp::GetProfileBinary, which would conflict with Crytek's memory manager.
		EditorMemoryUtils::operator delete[](pData);
	}
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::SaveLayouts()
{
	CXTPDockingPaneLayout layout(GetDockingPaneManager());
	GetDockingPaneManager()->GetLayout( &layout );
	layout.Save(TRACKVIEW_LAYOUT_SECTION);

	int colWidth, dummy;
	m_wndSplitter.GetColumnInfo(0, colWidth, dummy);
	AfxGetApp()->WriteProfileInt(TRACKVIEW_SECTION, SPLITTER_ENTRY, colWidth);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::ReadLayouts()
{
	CXTRegistryManager regMgr;
	int paneLayoutVersion = regMgr.GetProfileInt(TRACKVIEW_SECTION, VERSION_ENTRY, 0);
	if (paneLayoutVersion == TRACKVIEW_LAYOUT_VERSION)
	{
		CXTPDockingPaneLayout layout(GetDockingPaneManager());
		if (layout.Load(TRACKVIEW_LAYOUT_SECTION)) 
		{
			if (layout.GetPaneList().GetCount() > 0)
				GetDockingPaneManager()->SetLayout(&layout);	
		}

		int colWidth = regMgr.GetProfileInt(TRACKVIEW_SECTION, SPLITTER_ENTRY, 150);
		m_wndSplitter.SetPane(0, 0, &m_wndNodesCtrl, CSize(colWidth, 100));
	}
	else
	{
		regMgr.WriteProfileInt(TRACKVIEW_SECTION, VERSION_ENTRY, TRACKVIEW_LAYOUT_VERSION);
	}
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::SaveReBar() const
{
	CXTRegistryManager regMgr;
	regMgr.WriteProfileInt(TRACKVIEW_SETTINGS_SECTION, REBAR_VERSION_ENTRY, TRACKVIEW_REBAR_VERSION);

	unsigned int bandCount = m_rebar.GetReBarCtrl().GetBandCount();
	for(unsigned int i=0; i<bandCount; ++i)
	{
		CString bandEntry;
		bandEntry.Format("%s%d", REBAR_BAND_ENTRY_PREFIX, i);

		REBARBANDINFO rbi;
		ZeroMemory(&rbi,sizeof(REBARBANDINFO));
		rbi.cbSize = sizeof(REBARBANDINFO);
		rbi.fMask = RBBIM_ID |
			RBBIM_SIZE | RBBIM_STYLE
			// The following causes the app to remember rebar colors,
			// breaking windows theme changes.
			//RBBIM_COLORS |
			// The following causes the rebars to shift left on restore.
#if (_WIN32_IE >= 0x0400)
			| /*RBBIM_HEADERSIZE |*/ RBBIM_IDEALSIZE
#endif
			;
		m_rebar.GetReBarCtrl().GetBandInfo(i, &rbi);
		regMgr.WriteProfileBinary(TRACKVIEW_SETTINGS_SECTION, bandEntry, 
			reinterpret_cast<LPBYTE>(&rbi), rbi.cbSize);
	}
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::ReadReBar()
{
	CXTRegistryManager regMgr;
	int rebarVersion = regMgr.GetProfileInt(TRACKVIEW_SETTINGS_SECTION, REBAR_VERSION_ENTRY, 0);

	if(rebarVersion != TRACKVIEW_REBAR_VERSION)
		return;

	unsigned int bandCount = m_rebar.GetReBarCtrl().GetBandCount();
	for(unsigned int i=0; i<bandCount; ++i)
	{
		CString bandEntry;
		bandEntry.Format("%s%d", REBAR_BAND_ENTRY_PREFIX, i);

		LPBYTE pData;
		UINT size = 0;

		if(regMgr.GetProfileBinary(TRACKVIEW_SETTINGS_SECTION, bandEntry, 
				&pData, &size))
		{
			assert(size == sizeof(REBARBANDINFO));
			REBARBANDINFO rbi = *reinterpret_cast<REBARBANDINFO*>(pData);
			m_rebar.GetReBarCtrl().MoveBand(m_rebar.GetReBarCtrl().IDToIndex(rbi.wID), i);
			m_rebar.GetReBarCtrl().SetBandInfo(i, &rbi);
		}
	}
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::SetCursorPosText( float fTime )
{
	CString sText;
	int fps = FloatToIntRet(m_wndGraph.GetFPS());
	if(m_wndKeys.GetTickDisplayMode() == TVTICK_INSECONDS)
	{
		sText.Format("%1.3f(%dfps)", fTime, fps);
		m_CursorPos.SetWindowText(sText);
	}
	else if(m_wndKeys.GetTickDisplayMode() == TVTICK_INFRAMES)
	{
		sText.Format("%d(%dfps)", FloatToIntRet(fTime * m_wndGraph.GetFPS()), fps);
		m_CursorPos.SetWindowText(sText);
	}
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnCustomize()
{
	CMFCUtils::ShowShortcutsCustomizeDlg(GetCommandBars(), IDR_TRACKVIEW, "TrackView");
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnExportShortcuts()
{
	CMFCUtils::ExportShortcuts(GetCommandBars()->GetShortcutManager());
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnImportShortcuts()
{
	CMFCUtils::ImportShortcuts(GetCommandBars()->GetShortcutManager(), "TrackView");
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnBatchRender()
{
	CSequenceBatchRenderDialog dlg(m_wndGraph.GetFPS(), this);
	dlg.DoModal();
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnUpdateBatchRender( CCmdUI *pCmdUI)
{
	pCmdUI->Enable(GetMovieSystem()->GetNumSequences()>0?TRUE:FALSE);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::ClearTracksToolBar()
{
	while(m_tracksToolBar.GetToolBarCtrl().GetButtonCount()>0)
		m_tracksToolBar.GetToolBarCtrl().DeleteButton(0);

	m_pNodeForTracksToolBar = NULL;
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::AddButtonToTracksToolBar(int paramId, HICON hIcon)
{
	m_tracksToolBar.AddButton(ID_TV_TRACKS_TOOLBAR_BASE + paramId, hIcon);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnTracksToolBar( UINT nID )
{
	assert(m_pNodeForTracksToolBar);
	m_wndNodesCtrl.AddTrack(nID - ID_TV_TRACKS_TOOLBAR_BASE, m_pNodeForTracksToolBar);
}

//////////////////////////////////////////////////////////////////////////
BOOL CTrackViewDialog::OnToolTipTextForTracksToolBar(UINT, NMHDR* pNMHDR, LRESULT* pResult)
{
	TOOLTIPTEXTA *pTTTA = (TOOLTIPTEXTA *) pNMHDR;

	UINT_PTR nID = pNMHDR->idFrom;
	if (pNMHDR->code == TTN_NEEDTEXTA && !(pTTTA->uFlags & TTF_IDISHWND))
	{
		if (nID >= ID_TV_TRACKS_TOOLBAR_BASE && nID <= ID_TV_TRACKS_TOOLBAR_LAST)
		{
			assert(m_pNodeForTracksToolBar);
			IAnimNode::SParamInfo paramInfo;
			m_pNodeForTracksToolBar->GetParamInfoFromId(nID-ID_TV_TRACKS_TOOLBAR_BASE, paramInfo);
			int bufSize = (sizeof(pTTTA->szText) / sizeof(pTTTA->szText[0])); 
			sprintf_s(pTTTA->szText, bufSize, "Add %s Track", paramInfo.name);
			pTTTA->szText[bufSize-1] = 0;
			*pResult = 0;

			// Bring the tooltip window above other popup windows.
			::SetWindowPos(pNMHDR->hwndFrom, HWND_TOP, 0, 0, 0, 0,
				SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
		
		return TRUE;    // Message was handled
		}
	}

	return FALSE;
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::SaveZoomScrollSettings()
{
	if(m_currSequence == NULL)
		return;

	CSequenceObject* pObj = static_cast<CSequenceObject*>(m_currSequence->GetOwner());
	if(pObj == NULL)
		return;

	CSequenceObject::CZoomScrollSettings settings;
	settings.dopeSheetZoom = m_wndKeys.GetTimeScale();
	settings.dopeSheetHScroll = m_wndKeys.GetScrollPos(SB_HORZ);
	settings.nodesListVScroll = m_wndNodesCtrl.SaveVerticalScrollPos();
	settings.curveEditorZoom = m_wndGraph.GetSplineCtrl().GetZoom();
	settings.curveEditorScroll = m_wndGraph.GetSplineCtrl().GetScrollOffset();
	pObj->SetZoomScrollSettings(settings);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::CreateDefaultTracksForEntityNode(IAnimNode *pNode)
{
	IAnimNode::SParamInfo paramInfo;
	for(size_t i=0; i<m_defaultTracksForEntityNode.size(); ++i)
	{
		int count = (int)m_defaultTracksForEntityNode[i];
		GetMovieSystem()->GetEntityNodeParamInfo(i, paramInfo);
		assert(count < 2 || (paramInfo.flags&IAnimNode::PARAM_MULTIPLE_TRACKS));
		while(count--)
			pNode->CreateTrack(paramInfo.paramId);
	}
}

//////////////////////////////////////////////////////////////////////////
CString CTrackViewDialog::GetAvailableNameForDirectorNode() const
{
	assert(m_currSequence);

	int count = 0;
	CString name = "Director";
	while(true) 
	{
		bool bFound = false;
		for(int i=0; i<m_currSequence->GetNodeCount(); ++i)
		{
			IAnimNode *pNode = m_currSequence->GetNode(i);
			if(pNode->GetType() == ANODE_SCENE
			&& name == pNode->GetName())
			{
				bFound = true;
				break;
			}
		}
		if(bFound == false)
			break;
		++count;
		name.Format("Director #%d", count);
	}

	return name;
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnCreateLightAnimationSet()
{
	assert(GetIEditor()->GetMovieSystem()->FindSequence(LIGHT_ANIMATION_SET_NAME) == NULL);
	CUndo undo("Add Sequence");
	GetIEditor()->ExecuteCommand("trackview.new_sequence '%s'", LIGHT_ANIMATION_SET_NAME);
	IAnimSequence *pSequence = GetIEditor()->GetMovieSystem()->FindSequence(LIGHT_ANIMATION_SET_NAME);
	assert(pSequence);
	pSequence->SetFlags(IAnimSequence::LIGHT_ANIMATION_SET);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnAddLightAnimation()
{
	assert((m_currSequenceName == LIGHT_ANIMATION_SET_NAME) 
		&& (m_currSequence->GetFlags() & IAnimSequence::LIGHT_ANIMATION_SET));

	CStringDlg dlg("New Light Animation", this);
	while(true)
	{
		if(dlg.DoModal() == IDOK)
		{
			if(dlg.GetString().GetLength() > SRenderLight::kMaxLightAnimationNameLength)
			{
				CString msg;
				msg.Format("The max %d characters are allowed for the name of a light animation!", 
					SRenderLight::kMaxLightAnimationNameLength);
				AfxMessageBox(msg, MB_ICONEXCLAMATION|MB_OK);
				continue;
			}

			if(m_currSequence->FindNodeByName(dlg.GetString()))
			{
				CString msg;
				msg.Format("The name '%s' already exists!", dlg.GetString().GetString());
				AfxMessageBox(msg, MB_ICONEXCLAMATION|MB_OK);
				continue;
			}

			break;
		}
		else
		{
			return;
		}
	}

	CUndo undo("Add Node");
	CUndo::Record( new CUndoAnimSequenceObject(m_currSequence) );

	IAnimNode *pAnimNode = m_currSequence->CreateNode(ANODE_LIGHT);
	if (pAnimNode)
	{
		pAnimNode->SetName(dlg.GetString());
		pAnimNode->CreateTrack(APARAM_POS);
		pAnimNode->CreateTrack(APARAM_ROT);
		pAnimNode->CreateTrack(APARAM_LIGHT_DIFFUSECOLOR);
		pAnimNode->CreateTrack(APARAM_LIGHT_RADIUS);
		pAnimNode->SetFlags(pAnimNode->GetFlags()|ANODE_FLAG_SELECTED|ANODE_FLAG_EXPANDED);
		m_wndNodesCtrl.MoveJustCreatedNodeBelowSelected();
		GetIEditor()->Notify(eNotify_OnUpdateTrackView);
		m_wndNodesCtrl.SelectNode(pAnimNode->GetName());
	}
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnUpdateCreateLightAnimationSetUI( CCmdUI *pCmdUI )
{
	IAnimSequence *pSequence = GetIEditor()->GetMovieSystem()->FindSequence(LIGHT_ANIMATION_SET_NAME);
	if(pSequence && (pSequence->GetFlags() & IAnimSequence::LIGHT_ANIMATION_SET))
		pCmdUI->Enable(FALSE);
	else
		pCmdUI->Enable(TRUE);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnUpdateAddLightAnimationUI( CCmdUI *pCmdUI )
{
	bool bLightAnimationSetActive = (m_currSequenceName == LIGHT_ANIMATION_SET_NAME) 
		&& (m_currSequence->GetFlags() & IAnimSequence::LIGHT_ANIMATION_SET);
	
	if(bLightAnimationSetActive)
		pCmdUI->Enable(TRUE);
	else
		pCmdUI->Enable(FALSE);
}

//////////////////////////////////////////////////////////////////////////
void CTrackViewDialog::OnUpdateAddDirectorNodeUI( CCmdUI *pCmdUI )
{
	bool bLightAnimationSetActive = (m_currSequenceName == LIGHT_ANIMATION_SET_NAME) 
		&& (m_currSequence->GetFlags() & IAnimSequence::LIGHT_ANIMATION_SET);

	if(m_currSequence && !bLightAnimationSetActive)
		pCmdUI->Enable(TRUE);
	else
		pCmdUI->Enable(FALSE);
}
